package com.cloud.referenceTest;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 虚引用
 * 一个对象是否由虚引用的存在，完全不会对其生存时间构成影响，也无法通过虚引用来取得一个对象的实例
 * 为一个对象设置虚引用的唯一目的是为了能在这个对象被回收器回收的时候收到一个系统通知
 */
public class PhantomReferenceTest {
    //虚拟机设置 -Xms20M -Xmx20M

    private static final List<Object> LIST = new LinkedList<>();
    private static final ReferenceQueue<Student> QUEUE = new ReferenceQueue<>();

    public static void main(String[] args) {
        PhantomReference<Student> phantomReference = new PhantomReference<>(new Student(), QUEUE);
        System.out.println(phantomReference.get());

        new Thread(() -> {
            while (true) {
                LIST.add(new byte[1024 * 1024]);
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(phantomReference.get());
            }
        }).start();

        //模拟垃圾回收线程
        new Thread(() -> {
            while (true) {
                Reference<? extends Student> poll = QUEUE.poll();
                //虚引用指向的对象再被回收掉的时候会被放到 ReferenceQueue 中，如果这个队列有值了，就代表 phantomReference 对象被回收了
                if (poll != null) {
                    System.out.println("虚引用对象被回收了" + poll);
                    //如果这个对象指向了直接内存（堆外内存），因为GC管理不到直接内存，就需要通知 JVM 去清理掉对应的直接内存，什么时候清理由 JVM 决定
                    //……清理过程
                }
            }
        }).start();

        try{
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
